package com.edfu.core.contentmgt.jcr.service.impl;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Workspace;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionIterator;
import javax.jcr.version.VersionManager;

import org.apache.jackrabbit.JcrConstants;
import org.apache.log4j.Logger;

import com.edfu.core.contentmgt.jcr.commons.IMimeTypeService;
import com.edfu.core.contentmgt.jcr.commons.internal.MimeTypeServiceImpl;
import com.edfu.core.contentmgt.jcr.exception.DirectoryNameException;
import com.edfu.core.contentmgt.jcr.exception.DuplicateFileException;
import com.edfu.core.contentmgt.jcr.exception.FileNameException;
import com.edfu.core.contentmgt.jcr.exception.InvalidFileStreamException;
import com.edfu.core.contentmgt.jcr.exception.NoSuchDirectoryException;
import com.edfu.core.contentmgt.jcr.exception.NoSuchFileException;
import com.edfu.core.contentmgt.jcr.service.api.IContentMgtService;
import com.edfu.core.contentmgt.jcr.util.Constants;
import com.edfu.core.contentmgt.jcr.util.ContentMgtUtil;
import com.edfu.core.contentmgt.jcr.vo.Content;
import com.edfu.core.contentmgt.jcr.vo.ContentProperty;
import com.edfu.core.contentmgt.jcr.vo.Version;

public class ContentMgtServiceImpl implements IContentMgtService {
	private static Logger logger = Logger.getLogger(ContentMgtServiceImpl.class);

	IMimeTypeService mimeTypeService;
	ContentServiceAccessType accessType;
	private String workspaceName;
	private String userName;
	private String password;
	
/*	public ContentMgtServiceImpl() {
		userName = "admin";
		password = "admin";
		workspaceName = "default";
		accessType = ContentServiceAccessType.TRANSIENT;
	}*/

	public ContentMgtServiceImpl(String workspaceName,
			ContentServiceAccessType accessType) {
		mimeTypeService = new MimeTypeServiceImpl();
		this.accessType = accessType;
		this.workspaceName = workspaceName;
	}

	public ContentMgtServiceImpl(String workspaceName,
			ContentServiceAccessType accessType, String userName) {
		this.userName = userName;
		this.password = userName;
		mimeTypeService = new MimeTypeServiceImpl();
		this.accessType = accessType;
		this.workspaceName = workspaceName;
	}

	public ContentMgtServiceImpl(ContentServiceAccessType accessType) {
		mimeTypeService = new MimeTypeServiceImpl();
		this.accessType = accessType;
		this.workspaceName = "default";
	}

	public ContentMgtServiceImpl(ContentServiceAccessType accessType,
			String userName) {
		this.userName = userName;
		this.password = userName;
		mimeTypeService = new MimeTypeServiceImpl();
		this.workspaceName = "default";
		this.accessType = accessType;
	}

	@Override
	public Content addDirectory(String fullyQualifiedDirectoryName) {
		logger.debug("Start :: addDirectory");
		logger.debug("Fully Qualified directory name"
				+ fullyQualifiedDirectoryName);

		if (fullyQualifiedDirectoryName == null
				|| fullyQualifiedDirectoryName.equals("")) {
			logger.error(INVALID_DIRECTORY_NAME + " : "
					+ fullyQualifiedDirectoryName);
			throw new DirectoryNameException(INVALID_DIRECTORY_NAME + " : "
					+ fullyQualifiedDirectoryName);
		}

		Content content = null;
		Session session = null;
		try {
			session = _getUserSession();
			String[] dirName = fullyQualifiedDirectoryName.split("/");
			if (dirName == null || dirName.length == 0)
				return null;
			Node directoryNode = session.getRootNode();
			for (int i = 0; i < dirName.length; i++) {
				if (dirName[i].trim().equals(""))
					continue;
				if (directoryNode.hasNode(dirName[i])) {
					directoryNode = directoryNode.getNode(dirName[i]);
				} else {
					logger.debug("Adding node with name" + dirName[i]);
					directoryNode = directoryNode.addNode(dirName[i],
							JcrConstants.NT_UNSTRUCTURED);
					directoryNode.setProperty(Constants.EDU_NODETYPE, Constants.EDU_FOLDER);
				}
			}
			session.save();
			content = new Content();
			content.setContentUUID(directoryNode.getIdentifier());
			content.setFullyQualifiedContentName(directoryNode.getPath());
			content.setWorkspaceName(workspaceName);
		} catch (RepositoryException re) {
			logger.error(re);
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
			
		}
		logger.debug("End :: addDirectory");
		return content;
	}
	
	
	@Override
	public Content addDirectory(String fullyQualifiedDirectoryName, Map<String,String> properties) {
		logger.debug("Start :: addDirectory");
		logger.debug("Fully Qualified directory name"
				+ fullyQualifiedDirectoryName);

		if (fullyQualifiedDirectoryName == null
				|| fullyQualifiedDirectoryName.equals("")) {
			logger.error(INVALID_DIRECTORY_NAME + " : "
					+ fullyQualifiedDirectoryName);
			throw new DirectoryNameException(INVALID_DIRECTORY_NAME + " : "
					+ fullyQualifiedDirectoryName);
		}

		Content content = null;
		Session session = null;
		try {
			session = _getUserSession();
			String[] dirName = fullyQualifiedDirectoryName.split("/");
			if (dirName == null || dirName.length == 0)
				return null;
			Node directoryNode = session.getRootNode();
			for (int i = 0; i < dirName.length; i++) {
				if (dirName[i].trim().equals(""))
					continue;
				if (directoryNode.hasNode(dirName[i])) {
					directoryNode = directoryNode.getNode(dirName[i]);
				} else {
					logger.debug("Adding node with name" + dirName[i]);
					directoryNode = directoryNode.addNode(dirName[i],
							JcrConstants.NT_UNSTRUCTURED);
					directoryNode.setProperty(Constants.EDU_NODETYPE, Constants.EDU_FOLDER);
				}
			}
			if ( properties != null ) {
				for ( String propertyName : properties.keySet() ) {
					directoryNode.setProperty(propertyName, properties.get(propertyName));
				}
			}
			session.save();
			content = new Content();
			content.setContentUUID(directoryNode.getIdentifier());
			content.setFullyQualifiedContentName(directoryNode.getPath());
			content.setWorkspaceName(workspaceName);
		} catch (RepositoryException re) {
			logger.error(re);
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
			
		}
		logger.debug("End :: addDirectory");
		return content;
	}

	@Override
	public Content addFile(String fullyQualifiedFileName,
			Map<String, String> properties, InputStream is) {
		logger.debug("Start :: addFile");
		logger.debug("Fully Qualified file name" + fullyQualifiedFileName);

		Content content = null;

		if (fullyQualifiedFileName == null || fullyQualifiedFileName.equals("")) {
			logger.error(INVALID_FILE_NAME + " : " + fullyQualifiedFileName);
			throw new FileNameException(INVALID_FILE_NAME + " : "
					+ fullyQualifiedFileName);
		}
		
		if ( is == null ) {
			logger.error(NULL_FILE_STREAM);
			throw new InvalidFileStreamException(NULL_FILE_STREAM);
		}

		Session session = null;

		try {
			session = _getUserSession();
			String fileName = null;
			String directoryName = null;
			String[] dirName = null;
			if (fullyQualifiedFileName.indexOf("/") == -1) {
				fileName = fullyQualifiedFileName;
			} else {
				directoryName = fullyQualifiedFileName.substring(0,
						fullyQualifiedFileName.lastIndexOf("/"));
				fileName = fullyQualifiedFileName.substring(
						fullyQualifiedFileName.lastIndexOf("/") + 1,
						fullyQualifiedFileName.length());
				dirName = directoryName.split("/");
			}
			logger.debug("File Name" + fileName);

			String fileExtension = fileName.substring(
					fileName.lastIndexOf(".") + 1, fileName.length());
			logger.debug("File Extension" + fileExtension);

			if (dirName == null || dirName.length == 0) {
				logger.debug("No parent Directory of the file is present, so it will be added to the rootNode");
			}
			Node directoryNode = session.getRootNode();
			if (dirName != null)
				for (int i = 0; i < dirName.length; i++) {
					if (dirName[i].trim().equals(""))
						continue;
					if (directoryNode.hasNode(dirName[i])) {
						directoryNode = directoryNode.getNode(dirName[i]);
					} else {
						directoryNode = directoryNode.addNode(dirName[i],
								JcrConstants.NT_UNSTRUCTURED);
						directoryNode.setProperty(Constants.EDU_NODETYPE, Constants.EDU_FOLDER);
					}
				}
			if (directoryNode.hasNode(fileName)) {
				logger.debug("File with the name"
						+ fileName
						+ " already exists "
						+ " in the directory "
						+ directoryNode.getPath()
						+ ". A new file will be created in the same directory and previous one will not be overwritten");
			}
			Node fileNode = directoryNode.addNode(fileName,
					JcrConstants.NT_UNSTRUCTURED);
			fileNode.addMixin(JcrConstants.MIX_VERSIONABLE);
			fileNode.setProperty(Constants.EDU_NODETYPE, Constants.EDU_FOLDER);
			Node contentNode = fileNode.addNode(JcrConstants.JCR_CONTENT,
					JcrConstants.NT_RESOURCE);
			contentNode.setProperty(JcrConstants.JCR_MIMETYPE,
					mimeTypeService.getMimeType(fileExtension));
			contentNode.setProperty(JcrConstants.JCR_LASTMODIFIED,
					Calendar.getInstance());
			Binary binary = session.getValueFactory().createBinary(is);
			contentNode.setProperty(JcrConstants.JCR_DATA, binary);

			if (properties != null) {
				for (String key : properties.keySet()) {
					fileNode.setProperty(key, properties.get(key));
				}
			}
			logger.debug("Saving file");
			session.save();
			Workspace workspace = session.getWorkspace();
			VersionManager versionManager = workspace.getVersionManager();
			versionManager.checkin(fileNode.getPath());

			content = new Content();
			content.setContentUUID(fileNode.getIdentifier());
			content.setFullyQualifiedContentName(fileNode.getPath());
			content.setWorkspaceName(workspaceName);
		} catch (RepositoryException re) {
			logger.error(re);
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		logger.debug("End :: addFile");
		return content;
	}

	@Override
	public Content addFile(String fullyQualifiedFileName,
			Map<String, String> properties, File file) {
		if ( file == null ) {
			logger.error("NULL FILE PASSED") ;
			throw new InvalidFileStreamException("NULL FILE PASSED");
		}
		Content content = null;
		InputStream is = null;
		try {
			is = new BufferedInputStream(new FileInputStream(file));
			content = addFile(fullyQualifiedFileName, properties, is);
		} catch (FileNotFoundException e) {
			logger.error(e);
			throw new RuntimeException(e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					logger.error(e);
					throw (new RuntimeException(e.getMessage()));
				}
			}
		}
		return content;
	}

	@Override
	public void deleteDirectory(String fullyQualifiedDirectoryName) {
		if (fullyQualifiedDirectoryName == null
				|| fullyQualifiedDirectoryName.equals("")) {
			throw new DirectoryNameException(INVALID_DIRECTORY_NAME + " : "
					+ fullyQualifiedDirectoryName);
		}
		Session session = null;
		try {
			session = _getUserSession();
			Node directoryNode = switchNode(fullyQualifiedDirectoryName,
					session);
			if (directoryNode == null) {
				throw new NoSuchDirectoryException(NO_SUCH_DIRECTORY_WITH_NAME
						+ " : " + fullyQualifiedDirectoryName);
			}
			directoryNode.remove();
			session.save();
		} catch (RepositoryException e) {
			logger.error(e);
			throw new RuntimeException(e);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
	}
	
	@Override
	public void deleteFileWithUUID(String uuid) {
		Content content = null;
		Session session = null;
		try {
			session = _getUserSession();
			
			Node fileNode = null ;
			
			try {
				fileNode = session.getNodeByIdentifier(uuid);
			}catch (RepositoryException re) {
				throw new RuntimeException(re);
			}			
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_UUID + uuid
						+ " exists");
			}
			fileNode.remove();
			session.save();
		} catch (RepositoryException re) {
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}		
	}

	@Override
	public void deleteFile(String fullyQualifiedFileName) {
		if (fullyQualifiedFileName == null || fullyQualifiedFileName.equals("")) {
			throw new NoSuchFileException(INVALID_FILE_NAME + " : "
					+ fullyQualifiedFileName);
		}

		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = switchNode(fullyQualifiedFileName, session);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_NAME + " : "
						+ fullyQualifiedFileName);
			}
			fileNode.remove();
			session.save();
		} catch (RepositoryException e) {
			throw new RuntimeException(e);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}

	}

	@Override
	public void deleteFile(String fullyQualifiedFileName, String versionNumber) {
		if (fullyQualifiedFileName == null || fullyQualifiedFileName.equals("")) {
			throw new FileNameException(INVALID_FILE_NAME + " : "
					+ fullyQualifiedFileName);
		}

		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = switchNode(fullyQualifiedFileName, session);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_NAME + " : "
						+ fullyQualifiedFileName);
			}
			//Node contentNode = fileNode.getNode(JcrConstants.JCR_CONTENT);
			VersionManager versionManager = session.getWorkspace()
					.getVersionManager();
			VersionHistory versionHistory = versionManager
					.getVersionHistory(fileNode.getPath());
			 VersionIterator itr = versionHistory.getAllVersions();
	            while (itr.hasNext()) {
	                javax.jcr.version.Version version = itr.nextVersion();
	                if ( version.getName().equals(versionNumber)) {
	                	versionHistory.removeVersion(version.getName()) ;
	                }
	            }
//			Version version = versionHistory.getVersion(versionNumber);
//			//Remove reference of the version from the base version
//			
//			PropertyIterator versionReverences =version.getReferences() ;
//		    for (Property verRef = versionReverences.nextProperty(); versionReverences.hasNext();) {
//		        System.out.println("Name " + verRef.getName());
//		    }
//			versionHistory.removeVersion(version.getName());
			session.save();
		} catch (PathNotFoundException pnfe) {
			throw new NoSuchFileException(pnfe);
		} catch (RepositoryException e) {
			throw new RuntimeException(e);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
	}

	@Override
	public InputStream getFileAsStreamFromPath(String fullyQualifiedFileName) {
		return getFileDetailsFromPath(fullyQualifiedFileName)
				.getContentStream();
	}

	@Override
	public InputStream getFileAsStreamFromPath(String fullyQualifiedFileName,
			String versionNumber) {
		return getFileDetailsFromPath(fullyQualifiedFileName, versionNumber)
				.getContentStream();
	}

	@Override
	public InputStream getFileAsStreamFromUUID(String uuid) {
		return getFileDetailsFromUUID(uuid).getContentStream();
	}

	@Override
	public InputStream getFileAsStreamFromUUID(String uuid, String versionNumber) {
		return getFileDetailsFromUUID(uuid, versionNumber).getContentStream();
	}

	private Node switchNode(String path, Session session)
			throws PathNotFoundException, RepositoryException {
		if (path == null || path.trim().equals("")) {
			throw new DirectoryNameException(INVALID_DIRECTORY_NAME + " : "
					+ path);
		}
		Node currentNode = session.getRootNode();
		String[] dirName = path.split("/");

		if (dirName != null)
			for (int i = 0; i < dirName.length; i++) {
				if (dirName[i].trim().equals("")) {
					continue;
				}
				if (currentNode.hasNode(dirName[i])) {
					currentNode = currentNode.getNode(dirName[i]);
				} else {
					logger.error("No directory with name " + dirName[i] + "  "
							+ " found inside directory with name "
							+ currentNode.getPath());
					return null;
				}
			}
		return currentNode;
	}

	@Override
	public Version addFilePropertiesUsingPath(String fullyQualifiedFileName,
			Map<String, String> properties) {
		if (fullyQualifiedFileName == null || fullyQualifiedFileName.equals("")) {
			throw new FileNameException(INVALID_FILE_NAME + " : "
					+ fullyQualifiedFileName);
		}
		Version retVersion = null;
		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = session.getNode(fullyQualifiedFileName);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_NAME + " : "
						+ fullyQualifiedFileName);
			}
			session.getWorkspace().getVersionManager()
			.checkout(fullyQualifiedFileName);
			if (properties != null) {
				for (String key : properties.keySet()) {
					fileNode.setProperty(key, properties.get(key));
				}
			}	
			session.save();
			javax.jcr.version.Version  version = session.getWorkspace().getVersionManager()
					.checkin(fullyQualifiedFileName);
			//_printFileProperties(version.getFrozenNode());
			retVersion = new Version();
			retVersion.setVersionNumber(version.getName());
			retVersion.setContentUUID(version.getIdentifier());
			retVersion.setFullyQualifiedContentName(version.getPath());
			retVersion.setParentContentFullyQualifiedName(fileNode.getPath());
			retVersion.setParentContentUUID(fileNode.getIdentifier());
			retVersion.setWorkspaceName(workspaceName);
		} catch (PathNotFoundException pnfe) {
			throw new NoSuchFileException(pnfe);
		} catch (RepositoryException re) {
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return retVersion;
	}

	@Override
	public Version addFilePropertiesUsingUUID(String uuid,
			Map<String, String> properties) {
		if (uuid == null || uuid.equals("")) {
			throw new FileNameException(INVALID_FILE_UUID + " : " + uuid);
		}
		Version retVersion = null;
		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = session.getNodeByIdentifier(uuid);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_UUID + " : "
						+ uuid);
			}
			session.getWorkspace().getVersionManager()
			.checkout(fileNode.getPath());
			if (properties != null) {
				for (String key : properties.keySet()) {
					fileNode.setProperty(key, properties.get(key));
				}
			}
			session.save();
			javax.jcr.version.Version version = session.getWorkspace().getVersionManager()
					.checkin(fileNode.getPath());
			retVersion = new Version();
			retVersion.setVersionNumber(version.getName());
			retVersion.setContentUUID(version.getIdentifier());
			retVersion.setFullyQualifiedContentName(version.getPath());
			retVersion.setParentContentFullyQualifiedName(fileNode.getPath());
			retVersion.setParentContentUUID(fileNode.getIdentifier());
			retVersion.setWorkspaceName(workspaceName);
		} catch (PathNotFoundException pnfe) {
			throw new NoSuchFileException(pnfe);
		} catch (RepositoryException re) {
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return retVersion;
	}

	@Override
	public Version addVersion(
			String fullyQualifiedFileName, String versionNumber,
			Map<String, String> properties, InputStream is) {
		Version retVersion = null;
		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = switchNode(fullyQualifiedFileName, session);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_NAME + " : "
						+ fullyQualifiedFileName);
			}
			Workspace workspace = session.getWorkspace();
			VersionManager versionManager = workspace.getVersionManager();
			VersionHistory versionHistory = versionManager
					.getVersionHistory(fileNode.getPath());
			if (versionNumber != null
					&& versionNumber.trim().equalsIgnoreCase("") == false
					&& versionHistory.getVersionByLabel(versionNumber) != null) {
				throw new DuplicateFileException(
						"File Version with the following version number "
								+ versionNumber + " already exists");
			}

			versionManager.checkout(fileNode.getPath());
			String fileName = fullyQualifiedFileName.substring(
					fullyQualifiedFileName.lastIndexOf("/") + 1,
					fullyQualifiedFileName.length());

			String fileExtension = fileName.substring(
					fileName.lastIndexOf(".") + 1, fileName.length());
			Node contentNode = fileNode.getNode(JcrConstants.JCR_CONTENT);
			contentNode.setProperty(JcrConstants.JCR_MIMETYPE,
					mimeTypeService.getMimeType(fileExtension));
			contentNode.setProperty(JcrConstants.JCR_LASTMODIFIED,
					Calendar.getInstance());
			Binary binary = session.getValueFactory().createBinary(is);
			contentNode.setProperty(JcrConstants.JCR_DATA, binary);
			if (properties != null) {
				for (String key : properties.keySet()) {
					fileNode.setProperty(key, properties.get(key));
				}
			}
			session.save();
			javax.jcr.version.Version version = versionManager.checkin(fileNode.getPath());
			if (versionNumber != null)
				versionHistory.addVersionLabel(version.getName(),
						versionNumber, false);
			retVersion = new Version();
			retVersion.setContentUUID(version.getIdentifier());
			retVersion.setVersionNumber(version.getName());
			retVersion.setFullyQualifiedContentName(version.getPath());
			retVersion.setParentContentFullyQualifiedName(fileNode.getPath());
		} catch (PathNotFoundException pnfe) {
			throw new NoSuchFileException(pnfe);
		} catch (RepositoryException re) {
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return retVersion;
	}

	@Override
	public Version addVersion(
			String fullyQualifiedFileName, String versionNumber,
			Map<String, String> properties, File file) {
		Version version = null;
		InputStream is = null;
		try {
			is = new BufferedInputStream(new FileInputStream(file));
			version = addVersion(fullyQualifiedFileName, versionNumber,
					properties, is);
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e.getMessage());
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					throw (new RuntimeException(e.getMessage()));
				}
			}
		}
		return version;
	}

	@Override
	public Content addFile(String fullyQualifiedFileName, InputStream is) {
		return addFile(fullyQualifiedFileName, null, is);
	}

	@Override
	public Content addFile(String fullyQualifiedFileName, File file) {
		return addFile(fullyQualifiedFileName, null, file);
	}

	@Override
	public Version addVersion(
			String fullyQualifiedFileName, InputStream is) {
		return addVersion(fullyQualifiedFileName, null, null, is);
	}

	@Override
	public Version addVersion(
			String fullyQualifiedFileName, File file) {
		return addVersion(fullyQualifiedFileName, null, null, file);
	}

	@Override
	public Content getFileDetailsFromUUID(String uuid) {
		Content content = null;
		Session session = null;
		try {
			session = _getUserSession();
			
			Node fileNode = null ;
			
			try {
				fileNode = session.getNodeByIdentifier(uuid);
			}catch (RepositoryException re) {
				
			}
			
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_UUID + uuid
						+ " exists");
			}
			Node contentNode = fileNode.getNode(JcrConstants.JCR_CONTENT);
			Property data = contentNode.getProperty(JcrConstants.JCR_DATA);
			InputStream is = new BufferedInputStream(data.getBinary()
					.getStream());
			content = new Content();
			content.setContentUUID(fileNode.getIdentifier());
			content.setContentStream(is);
			content.setFullyQualifiedContentName(fileNode.getPath());
			content.setWorkspaceName(workspaceName);
		} catch (RepositoryException re) {
			throw new RuntimeException(re);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return content;
	}

	@Override
	public Version getFileDetailsFromUUID(String uuid,
			String versionNumber) {
		Version retVersion = null;
		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = session.getNodeByIdentifier(uuid);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_UUID
						+ uuid + " exists");
			}
			Workspace workspace = session.getWorkspace();
			VersionManager versionManager = workspace.getVersionManager();
			VersionHistory versionHistory = versionManager
					.getVersionHistory(fileNode.getPath());
			javax.jcr.version.Version version = versionHistory.getVersion(versionNumber);
			if (version == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_UUID
						+ fileNode.getIdentifier() + "and version "
						+ versionNumber + " exists");
			}
			Node frozenNode = version.getFrozenNode();
			Node contentNode = frozenNode.getNode(JcrConstants.JCR_CONTENT);
			Property data = contentNode.getProperty(JcrConstants.JCR_DATA);
			InputStream is = new BufferedInputStream(data.getBinary()
					.getStream());
			retVersion = new Version();
			retVersion.setContentStream(is);
			retVersion.setVersionNumber(version.getName());
			retVersion.setContentUUID(version.getIdentifier());
			retVersion.setFullyQualifiedContentName(version.getPath());
			retVersion.setParentContentFullyQualifiedName(fileNode.getPath());
			retVersion.setParentContentUUID(fileNode.getIdentifier());
			retVersion.setWorkspaceName(workspaceName);
			List<ContentProperty> contentProperties = new ArrayList<ContentProperty>();
			PropertyIterator it = version.getFrozenNode().getProperties() ;
			while(it.hasNext()) {
				Property property = it.nextProperty() ;
				if (property.getName().startsWith("jcr:"))
					continue;
				ContentProperty contentProperty = new ContentProperty();
				contentProperty.setPropertyName(property.getName());
				contentProperty.setPropertyValue(property.getValue().getString()) ;
				contentProperties.add(contentProperty);
			}
			retVersion.setProperties(contentProperties);
		} catch (RepositoryException re) {
			throw new RuntimeException(re);
		}finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return retVersion;
	}


	@Override
	public Content getFileDetailsFromPath(String fullyQualifiedFileName) {
		Content content = null;
		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = switchNode(fullyQualifiedFileName, session);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_NAME
						+ fullyQualifiedFileName + " exists");
			}
			Node contentNode = fileNode.getNode(JcrConstants.JCR_CONTENT);
			Property data = contentNode.getProperty(JcrConstants.JCR_DATA);
			InputStream is = new BufferedInputStream(data.getBinary()
					.getStream());

			content = new Content();
			content.setContentUUID(fileNode.getIdentifier());
			content.setContentStream(is);
			content.setFullyQualifiedContentName(fileNode.getPath());
			content.setWorkspaceName(workspaceName);
		} catch (PathNotFoundException e) {
			throw (new RuntimeException(e));
		} catch (RepositoryException e) {
			throw (new RuntimeException(e));
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return content;
	}

	@Override
	public Version getFileDetailsFromPath(
			String fullyQualifiedFileName, String versionNumber) {
		Version retVersion = null;
		Session session = null;
		try {
			session = _getUserSession();
			Node fileNode = switchNode(fullyQualifiedFileName, session);
			if (fileNode == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_NAME
						+ fullyQualifiedFileName + " exists");
			}
			Workspace workspace = session.getWorkspace();
			VersionManager versionManager = workspace.getVersionManager();
			VersionHistory versionHistory = versionManager
					.getVersionHistory(fileNode.getPath());
			javax.jcr.version.Version version = null;
			for (VersionIterator it = versionHistory.getAllVersions(); it
					.hasNext();) {
				javax.jcr.version.Version temp = (javax.jcr.version.Version) it.next();
				if (temp.getName().equalsIgnoreCase(versionNumber)) {
					version = temp;
					break;
				}
			}
			if (version == null) {
				throw new NoSuchFileException(NO_SUCH_FILE_WITH_NAME
						+ fullyQualifiedFileName + "and version "
						+ versionNumber + " exists");
			}

			Node frozenNode = version.getFrozenNode();
			Node contentNode = frozenNode.getNode(JcrConstants.JCR_CONTENT);
			Property data = contentNode.getProperty(JcrConstants.JCR_DATA);
			InputStream is = new BufferedInputStream(data.getBinary()
					.getStream());
			retVersion = new Version();
			retVersion.setContentStream(is);
			retVersion.setVersionNumber(version.getName());
			retVersion.setContentUUID(version.getIdentifier());
			retVersion.setFullyQualifiedContentName(version.getPath());
			retVersion.setParentContentFullyQualifiedName(fileNode.getPath());
			retVersion.setParentContentUUID(fileNode.getIdentifier());
			retVersion.setWorkspaceName(workspaceName);
			List<ContentProperty> contentProperties = new ArrayList<ContentProperty>();
			PropertyIterator it = version.getFrozenNode().getProperties() ;
			while(it.hasNext()) {
				Property property = it.nextProperty() ;
				if (property.getName().startsWith("jcr:"))
					continue;
				ContentProperty contentProperty = new ContentProperty();
				contentProperty.setPropertyName(property.getName());
				contentProperty.setPropertyValue(property.getValue().getString()) ;
				contentProperties.add(contentProperty);
			}
			retVersion.setProperties(contentProperties);
		} catch (PathNotFoundException e) {
			throw (new RuntimeException(e));
		} catch (RepositoryException e) {
			throw (new RuntimeException(e));
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return retVersion;
	}

	public List<Version> getAllVersions(String filePath) {
		 List<Version> versions = new ArrayList<Version>();
		Session session = null;
		try {
			session = _getUserSession();
			VersionManager manager = session.getWorkspace().getVersionManager();
			VersionHistory history = manager.getVersionHistory(filePath);
			for (VersionIterator itr = history.getAllVersions(); itr.hasNext();) {
				javax.jcr.version.Version version = itr.nextVersion();
				versions.add(ContentMgtUtil.convertJCRVersionToEduVersion(version, filePath));
				logger.debug("***************************");
				logger.debug("Version Name " + version.getName() );
				logger.debug("***************************");
			}
		} catch (RepositoryException e) {
			logger.error(e);
			throw new RuntimeException(e);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return versions;
	}


	private Session _getUserSession() {
		Session currentUserSession = null;
		try {
			currentUserSession = JCRFactoryUtil.createSession(userName,
					password, workspaceName, accessType);
		}  catch (RepositoryException e) {
			if (e.getMessage().contains("Unauthorized")) {
				_createUser(userName, password);
				try {
					currentUserSession = JCRFactoryUtil.createSession(userName,
							password, workspaceName, accessType);
				} catch (RepositoryException e1) {
					throw new RuntimeException(e1);
				}
			}else {
				logger.error(e);
				throw new RuntimeException(e);
			}
		}
		return currentUserSession;
	}

	@SuppressWarnings("deprecation")
	private void _createUser(String username, String password) {
		HttpURLConnection conn = null;
		try {
			String encodedUserName = URLEncoder.encode(username);
			String encodedPassword = URLEncoder.encode(password);
			//Temporary , needs th be changed 
			String urlAsStr = "http://localhost:8080/jackrabbit/usermanager?userName="
					+ encodedUserName + "&password=" + encodedPassword;
			URL url = new URL(urlAsStr);
			conn = (HttpURLConnection) url.openConnection();
			// conn.setRequestMethod("GET");
			conn.setDoOutput(true);
			PrintWriter out = new PrintWriter(conn.getOutputStream());
			out.println();
			out.flush();
			out.close();
			conn.getInputStream();
			conn.disconnect();
		} catch (MalformedURLException e) {
			logger.error(e);
			throw new RuntimeException(e);
		} catch (IOException e) {
			logger.error(e);
			throw new RuntimeException(e);
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	@Override
	public List<Content> getChildren(String parentAbsolutePath) {
		List<Content> children = new ArrayList<Content>();
		Session session = null;
		try {
			session = _getUserSession();
			Node parentNode = session.getNode(parentAbsolutePath) ;
			Content content = ContentMgtUtil.convertJCRNodeToEduContent(parentNode);
			children = populateChildrenData(parentNode,content.getChildren());
		} catch (PathNotFoundException e) {
			logger.error(e);
			throw new RuntimeException(e);
		} catch (RepositoryException e) {
			logger.error(e);
			throw new RuntimeException(e);
		} finally {
			if (session != null && session.isLive()) {
				session.logout();
			}
		}
		return children;
	}
	
	private List<Content > populateChildrenData(Node node, List<Content> children) throws RepositoryException {
		NodeIterator itr = node.getNodes();
		while (itr.hasNext()) {
			Node childAsNode = itr.nextNode();
			Content childAsContent = ContentMgtUtil.convertJCRNodeToEduContent(childAsNode) ;
			children.add(childAsContent); 
			if ( childAsNode.getNodes().getSize() > 0) {
				populateChildrenData(childAsNode, childAsContent.getChildren());
			}
		} 
		return children;
	}

}
